#pragma once

#define ELIST_LINKAGE(CLASS_NAME) \
	public: \
		CLASS_NAME* Next; \
		CLASS_NAME* Prev; \

namespace gecko
{

	namespace gtl
	{

		// forward declare types
		namespace internal { template<typename T> class EListIterator; }
		
		// Templated list class with links embedded in the class itself.
		template < typename T >
		class EList
		{
		public:
			typedef internal::EListIterator<const T> ConstIterator;
			typedef internal::EListIterator<T> Iterator;

			// Constructor
			EList();

			// Copy constructor
			EList(const EList& list);

			// Get an iterator pointing to the start of the list
			Iterator Begin();

			// Get an iterator pointing to the end of the list
			Iterator End();

			// Get a const iterator pointing to the start of the list
			ConstIterator Begin() const;

			// Get a const iterator pointing to the end of the list
			ConstIterator End() const;

			// Insert an item of data before another
			void Insert(T& data, Iterator before);

			// Erase an item from the list
			void Erase(Iterator where);

			// Remove an item from the list (unlinks node directly)
			void Remove(const T& data);

			// Find an item in the list (searches linearly O(n))
			Iterator Find(const T& data);

			// Find an item in the list (searches linearly O(n)) - const version
			ConstIterator Find(const T& data) const;

			// Push an item onto the back of the list
			void PushBack(T& data);

			// Push an item onto the front of the list
			void PushFront(T& data);

			// Pop an item off the front of the list
			void PopFront();

			// Pop an item off the back of the list
			void PopBack();

			// Get the item on the front of the list
			T& Front();

			// Get the item on the front of the list (const version)
			const T& Front() const;

			// Get the item on the back of the list
			T& Back();

			// Get the item on the back of the list (const version)
			const T& Back() const;

			// Clear the list and delete all the nodes
			void Clear();

			// Get the number of items in the list
			unsigned int Size();

			// Test if the list is empty
			bool Empty();

		private:
			T* m_Head;
			T* m_Tail;
			unsigned int m_Count;

			friend class internal::EListIterator<const T>;
			friend class internal::EListIterator<T>;
		};

	}

}

#include "elist.inl"
